package com.ws.shop.util.file;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.util.Properties;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.apache.log4j.Logger;
import org.dom4j.Document;

import com.ws.shop.util.StringUtil;



/**
 * 文件处理公共工具类.
 * 
 * @author shannon
 * @version 1.0 , 2008-5-29
 * @since JDK1.4
 */
public class FileUtil {
	private static Logger log = Logger.getLogger(FileUtil.class);

	/**
	 * 默认构造函数 为私有，不能实例化。
	 */
	private FileUtil() {

	}

	/**
	 * 获取文件路径的全名
	 * 
	 * @param path
	 *            文件路径
	 * @return 文件路径带“/”结束
	 */
	public static String realPath(String path) {
		if (null == path)
			return null;
		StringBuffer sb = new StringBuffer(path);
		if (!path.endsWith("/") && !path.endsWith("\\")) {
			sb.append("/");
		}
		return sb.toString();
	}

	/**
	 * 根据目录及文件名获取文件路径
	 * 
	 * @param dir
	 *            文件路径
	 * @param fileName
	 *            文件名
	 * @return 文件路径
	 */
	public static String getFilePath(String dir, String fileName) {
		if (dir == null || fileName == null) {
			return null;
		}
		StringBuffer sb = new StringBuffer();
		sb.append(dir);
		if (!dir.endsWith(File.separator)) {
			sb.append(File.separator);
		}
		sb.append(fileName);
		return sb.toString();
	}

	/**
	 * 创建文件路径
	 * 
	 * @param dir
	 *            文件路径
	 */
	public static void createDir(String dir) {
		if (!StringUtil.isEmpty(dir)) {
			File file = new File(dir);
			if (!file.exists()) {
				log.warn("mkdir :" + dir);
				file.mkdirs();
			}
		}
	}

	/**
	 * 保存XML字符串报文到文件中
	 * 
	 * @param fileName
	 *            文件名（全路径）
	 * @param xml
	 *            XML字符串
	 */
	public static void saveXmlToFile(String fileName, String xml,boolean append) {
		saveDataToFile(fileName, xml,append);
	}

	/**
	 * 保存Document报文到文件
	 * 
	 * @param fileName
	 *            文件名（全路径）
	 * @param doc
	 *            Document报文
	 */
	public static void saveXmlToFile(String fileName, Document doc,boolean append) {
		saveXmlToFile(fileName, doc.asXML(),append);
	}

	/**
	 * 保存XML字符串报文到文件中
	 * 
	 * @param fileName
	 *            文件名（全路径）
	 * @param xml
	 *            XML字符串
	 */
	public static void saveXmlToFile_dirExisted(String fileName, String xml,boolean append) {
		saveDataToFile_dirExisted(fileName, xml,append);
	}

	/**
	 * 
	 * 读取文件内容转为字符串
	 * 
	 * @param file
	 *            文件名（全路径）
	 * @return 字符串
	 * @throws IOException
	 */
	public static String fileToString(File file) throws IOException {
		RandomAccessFile rfile = null;
		try {
			rfile = new RandomAccessFile(file, "r");
			int len = (int) (rfile.length());
			byte[] bytes = new byte[len];
			rfile.read(bytes, 0, len);
			String msg = new String(bytes);
			return msg;
		} catch (IOException ex) {
			log.error("fileToString Error:",ex);
			throw ex;
		} finally {
			try {
				if (null != rfile)
					rfile.close();
			} catch (IOException e) {
				log.error("RandomAccessFile close Error:",e);
			}
		}
	}

	/**
	 * 读取文件内容转为字符串
	 * 
	 * @param file
	 *            文件名
	 * @param encode
	 *            编码
	 * @return 字符串
	 * @throws IOException
	 */
	public static String fileToString(File file, String encode)
			throws IOException {
		RandomAccessFile rfile = null;
		try {
			rfile = new RandomAccessFile(file, "r");
			int len = (int) (rfile.length());
			byte[] bytes = new byte[len];
			rfile.read(bytes, 0, len);
			String msg = new String(bytes, encode);
			return msg;
		} catch (IOException ex) {
			log.error("fileToString Error:" ,ex);
			throw ex;
		} finally {
			try {
				if (rfile != null)
					rfile.close();
			} catch (IOException e) {
				log.error("RandomAccessFile close Error:",e);
			}
		}
	}

	/**
	 * 
	 * 读取文件内容转为字符串
	 * 
	 * @param file
	 *            文件名（全路径）
	 * @return 字符串
	 * @throws IOException
	 */
	public static String fileToString(String file) throws Exception {
		RandomAccessFile rfile = null;
		try {
			rfile = new RandomAccessFile(file, "r");
			int len = (int) (rfile.length());
			byte[] bytes = new byte[len];
			rfile.read(bytes, 0, len);
			String msg = new String(bytes);
			return msg;
		} catch (Exception ex) {
			log.error("fileToString Error:",ex);
			throw ex;
		} finally {
			try {
				if (null != rfile)
					rfile.close();
			} catch (IOException e) {
				log.error("RandomAccessFile close Error:",e);
			}
		}
	}

	/**
	 * 
	 * 读取文件内容转为字符串
	 * 
	 * @param file
	 *            文件名（全路径）
	 * @return 字符串
	 * @throws IOException
	 */
	public static String fileToString(String file, String encode)
			throws Exception {
		RandomAccessFile rfile = null;
		try {
			rfile = new RandomAccessFile(file, "r");
			int len = (int) (rfile.length());
			byte[] bytes = new byte[len];
			rfile.read(bytes, 0, len);
			String msg = new String(bytes, encode);
			return msg;
		} catch (Exception ex) {
			log.error("fileToString Error:",ex);
			throw ex;
		} finally {
			try {
				if (null != rfile)
					rfile.close();
			} catch (IOException e) {
				log.error("RandomAccessFile close Error:",e);
			}
		}
	}

	/**
	 * 保存字符串内容到文件中
	 * 
	 * @param fileName
	 *            文件名（全路径）
	 * @param str
	 *            字符串
	 */
	public static void saveDataToFile(String fileName, String str,boolean append) {
		checkFile(fileName);
		log.warn("saveDataToFile:" + fileName);
		FileOutputStream fos = null;
		PrintStream out = null;
		try {
			fos = new FileOutputStream(fileName, append);
			out = new PrintStream(new BufferedOutputStream(fos));
			out.println(str);
		} catch (Exception e) {
			log.error("saveRecordToFile  error:",e);
		} finally {
			if (null != out)
				out.close();
			try {
				if (null != fos)
					fos.close();
			} catch (IOException e) {
				log.error("FileOutputStream close error:",e);
			}
		}
	}

	/**
	 * 保存字符串内容到文件中
	 * 
	 * @param fileName
	 *            文件名（全路径）
	 * @param str
	 *            字符串
	 */
	public static void saveDataToFile(String fileName, String str,
			String uncode,boolean append) {
		checkFile(fileName);
		log.warn("saveDataToFile:" + fileName);
		try {
			File NewFile = new File(fileName);
			OutputStream tempOutputStream = new FileOutputStream(NewFile,append);
			BufferedWriter bufferedWriter = new BufferedWriter(
					new OutputStreamWriter(tempOutputStream, uncode));
			bufferedWriter.write(str);
			bufferedWriter.flush();
			bufferedWriter.close();
		} catch (Exception e) {
			log.error("saveRecordToFile  error:" ,e);
		}
	}

	/**
	 * 保存字符串内容到文件中
	 * 
	 * @param fileName
	 *            文件名（全路径）
	 * @param str
	 *            字符串
	 */
	public static void saveDataToFile_dirExisted(String fileName, String str,boolean append) {
		log.warn("saveDataToFile:" + fileName);
		FileOutputStream fos = null;
		PrintStream out = null;
		try {
			fos = new FileOutputStream(fileName, append);
			out = new PrintStream(new BufferedOutputStream(fos));
			out.println(str);
		} catch (Exception e) {
			log.error("saveRecordToFile  error:",e);
		} finally {
			if (null != out)
				out.close();
			try {
				if (null != fos)
					fos.close();
			} catch (IOException e) {
				log.error("FileOutputStream close error:",e);
			}
		}
	}

	/**
	 * 检查文件的父节点是否存在，不存在则建立
	 * 
	 * @param fileName
	 *            文件名
	 */
	private static void checkFile(String fileName) {
		File file = new File(fileName);
		File parent = file.getParentFile();
		if (null == parent || !parent.exists())
			parent.mkdirs();
	}

	/**
	 * 将数据写入文件，使用回调接口 。<br>
	 * <P>
	 * 多用于循环处理数据，并需要把数据写入同一文件。通过回调避免多次打开IO
	 * 
	 * @param fileName
	 *            文件名
	 * @param pps
	 *            ProcPrintStream回调接口 通过PrintStream实现
	 * @throws Exception
	 */
	public static void saveDataToFile(String fileName, ProcPrintStream pps)
			throws Exception {
		checkFile(fileName);
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		PrintStream ps = null;
		try {
			fos = new FileOutputStream(fileName, true);
			bos = new BufferedOutputStream(fos);
			ps = new PrintStream(bos);
			pps.proc(ps);
		} catch (Exception e) {
			log.error("saveRecordToFile  error:" ,e);
			throw e;
		} finally {
			if (null != ps)
				ps.close();
			if (null != bos)
				bos.close();
			try {
				if (null != fos)
					fos.close();
			} catch (IOException e) {
				log.error("FileOutputStream close error:",e);
			}
		}
	}

	/**
	 * 
	 * 将数据写入文件，使用回调接口 。<br>
	 * <P>
	 * 多用于循环处理数据，并需要把数据写入同一文件。通过回调避免多次打开IO
	 * 
	 * @param fileName
	 *            文件名
	 * @param pbw
	 *            ProcBufferedWriter 回调接口， 通过BufferedWriter实现
	 * @throws Exception
	 */
	public static void saveDataToFile(String fileName, ProcBufferedWriter pbw)
			throws Exception {
		checkFile(fileName);
		FileWriter fw = null;
		BufferedWriter bw = null;
		try {
			fw = new FileWriter(fileName, true);
			bw = new BufferedWriter(fw);
			pbw.proc(bw);
		} catch (Exception e) {
			log.error("saveRecordToFile  error:",e);
			throw e;
		} finally {
			if (null != bw)
				bw.close();
			if (null != fw)
				fw.close();
		}
	}

	/**
	 * 
	 * 从文件中读取数据，使用回调接口。 <br>
	 * <P>
	 * 多用于文件中存在多条数据需要处理，通过回调避免多次打开IO
	 * 
	 * @param fileName
	 *            文件名(全路径)
	 * @param pbr
	 *            ProcBufferedReader回调接口 通过BufferedReader实现
	 * @throws Exception
	 */
	public static void readRecordFromFile(String fileName,
			ProcBufferedReader pbr) throws Exception {
		FileReader fr = null;
		BufferedReader br = null;
		try {
			fr = new FileReader(fileName);
			br = new BufferedReader(fr);
			pbr.proc(br);
		} catch (Exception e) {
			log.error("readRecordFromFile  error:" ,e);
			throw e;
		} finally {
			if (null != br)
				br.close();
			if (null != fr)
				fr.close();
		}
	}

	/**
	 * 
	 * 从文件中读取数据，使用回调接口。 <br>
	 * <P>
	 * 多用于文件中存在多条数据需要处理，通过回调避免多次打开IO
	 * 
	 * @param file
	 *            文件
	 * @param pbr
	 *            ProcBufferedReader 回调接口，调用BufferedReader实现
	 * @throws Exception
	 */
	public static void readRecordFromFile(File file, ProcBufferedReader pbr)
			throws Exception {
		FileReader fr = null;
		BufferedReader br = null;
		try {
			fr = new FileReader(file);
			br = new BufferedReader(fr);
			pbr.proc(br);
		} catch (Exception e) {
			log.error("readRecordFromFile  error:" ,e);
			throw e;
		} finally {
			if (null != fr)
				fr.close();
			if (null != br)
				br.close();

		}
	}

	/**
	 * 将源文件压缩为目标文件 （仅限于ZIP格式）
	 * 
	 * @param file
	 *            源文件
	 * @param targetFile
	 *            目标文件
	 */
	public static void gZIP(File file, String targetFile) {
		InputStream is = null;
		BufferedOutputStream bos = null;
		try {
			is = new FileInputStream(file);
			bos = new BufferedOutputStream(new GZIPOutputStream(
					new FileOutputStream(targetFile)));
			int n = is.available();
			byte ko[] = new byte[n];
			is.read(ko);
			for (int m = 0; m < n; m++)
				bos.write(ko[m]);
		} catch (Exception ex) {
			log.error("gZip error:" ,ex);
		} finally {
			try {
				if (null != is)
					is.close();
			} catch (IOException e) {
				log.error("InputStream close error:",e);
			}
			try {
				if (bos != null)
					bos.close();
			} catch (IOException e) {
				log.error("BufferedOutputStream close error:",e);
			}
		}
	}

	/**
	 * 将压缩文件解压为目标文件 （仅限于ZIP格式）
	 * 
	 * @param zipFile
	 *            压缩文件
	 * @param targetFile
	 *            目标文件
	 */
	public static void gunZIP(File zipFile, String targetFile) {
		InputStream is = null;
		BufferedOutputStream bos = null;
		try {
			is = new GZIPInputStream(new FileInputStream(zipFile));
			bos = new BufferedOutputStream(new FileOutputStream(targetFile));
			int n1 = is.available();
			byte ko[] = new byte[n1];
			int num1 = 0;
			while ((num1 = is.read(ko, 0, ko.length)) != -1) {
				bos.write(ko, 0, num1);
			}
		} catch (Exception ex) {
			log.error("gunZIP error:",ex);
		} finally {
			try {
				if (null != bos)
					bos.close();
			} catch (IOException e) {
				log.error("BufferedOutputStream close error:",e);
			}
			try {
				if (null != is)
					is.close();
			} catch (IOException e) {
				log.error("InputStream close error:",e);
			}
		}
	}

	/**
	 * 将包路径转换为相对路径
	 * 
	 * @param packagePath
	 *            包路径
	 * @return 相对路径
	 */
	public static String getPhyPath(String packagePath) {
		return packagePath.replace('.', '/');
	}

	/**
	 * 获取相对路径文件名
	 * 
	 * @param bundleName
	 *            包路径
	 * @param SUFFIX
	 *            文件后缀
	 * @return 文件名
	 */
	private static String getFileName(String bundleName, String SUFFIX) {
		return bundleName.replace('.', '/') + SUFFIX;
	}

	/**
	 * 从包路径获取文件绝对路径名
	 * 
	 * @param bundleName
	 *            包路径
	 * @param SUFFIX
	 *            文件后缀
	 * @return 文件绝对路径名
	 */
	public static String getFileRealPath(String bundleName, String SUFFIX) {
		return FileUtil.class.getClassLoader().getResource(
				getFileName(bundleName, SUFFIX)).getFile();
	}

	/**
	 * 从包路径获取文件绝对路径名 例如：com/hontoot/util/log4j.properties
	 * 
	 * @param bundleName
	 * @return
	 */
	public static String getFileRealPath(String bundleName) {
		return FileUtil.class.getClassLoader().getResource(bundleName)
				.getFile();
	}
	
	/**
	 * 移动文件
	 * @param srcFile
	 * @param destFile
	 */
	public static void move(String srcFile,String destFile){
		File src = new File(srcFile);
		File dest = new File(destFile);
		src.renameTo(dest);
	}
	
}
